import re

def nsep(line, sep=' '): # 获取缩进数量
    for i in range(len(line)):
        if line[i] != sep: return i
    return len(line)

def gauss_type(field): # 猜测数据类型
    keys = {'()':'tuple', '[]':'list', '{}':'dict'}
    if field in keys: return keys[field]
    if re.match('^[a-zA-Z|_][\w|.]*\(\)$', field): return 'func'
    if re.match('^[a-zA-Z|_][\w|.]*$', field): return 'var'
    return 'None'
    
def clear_para(ps): # 从函数定义获取参数列表
    ps = [i for i in ps.split(',') if i!='']
    ps = [i.replace('*','') for i in ps]
    ps = [i.split('=')[0] for i in ps]
    return [i for i in ps if i != 'self']

def filter_field(ls, rs):
    nls, nrs = [], []
    for l, r in zip(ls, rs):
        if gauss_type(l) != 'var': continue
        if not gauss_type(r) in {'func', 'var'}:
            r = gauss_type(r)
        nls.append(l); nrs.append(r)
    return nls, nrs
    
def parse_field(line): # 解析字段
    line = line.replace('==', '*')
    line = line.replace(' ', '')
    # for i in ' ()': line = line.replace(i, '')
    seps, ls, rs = line.split('='), [], []
    for i in seps[:-1]:
        l, r = i.split(','), seps[-1].split(',')
        if len(l)==1 and len(r)>1: r = ['()']
        if len(l) != len(r): r = ['None'] * len(l)
        ls.extend(l); rs.extend(r)
    # return filter_field(ls, rs)
    return ls, rs

def parse_function(line): # 解析函数定义
    line = line.split(':')[0]
    for i in ' )': line = line.replace(i, '')
    if not '(' in line: return None, None
    name, para = line[3:].split('(')[:2]
    return name, clear_para(para)

def parse_class(line): # 解析类定义
    for i in ' :)': line = line.replace(i, '')
    name, base = (line[5:].split('(')+['None'])[:2]
    return name, base.split(',')

# self 关联到类，局部找不到向全局搜索
def abs_path(path, name, contex, objs, funcs, new=False):
    if name == '': return path
    ns = name.split('.')
    if ns[0]=='self':
        while len(path)>0 and path in contex:
            if contex[path][0] == 'class':
                return path+'.'+'.'.join(ns[1:])
            path = '.'.join(path.split('.')[:-1])
    def rm(line):
        while line[-2:] in {'()', '[]'}:
            line = line[:-2]
        return line
    if path + '.' + rm(name) in contex or new:
        return path + '.' + name
    if 'root.'+rm(ns[0]) in contex: return 'root.'+name
    return name

# 如果是变量类型的，递归溯源，找到最终类型
def abs_type(expr, contex, objs, funcs, deepin=True):
    # print(expr, ' exprrrrrrr', deepin)
    # expr, post = (expr[:-2],'()') if expr[-2:]=='()' else (expr,'')
    if expr in contex or expr[:-2] in contex and expr[-2:]=='()':
        if expr[-2:]!='()': # 非函数，返回类型
            if contex[expr][0]=='class': return ('var', expr)
            return ('var', contex[expr][1])
        elif contex[expr[:-2]][0]=='class': # 类函数返回自身
            return ('var', expr[:-2])
    if expr in funcs: return ('var', funcs[expr])
    if not deepin: return ('var', expr)

    if expr[-2:] in {'()', '[]'}:
        pre = abs_type(expr[:-2], contex, objs, funcs)
        if pre[1] is None: return ('var', expr)
        return abs_type(pre[1]+expr[-2:], contex, objs, funcs, False)
    if '.' in expr: # 如果是长表达式，按照点向前拆分
        ns = (expr).split('.')
        pre = abs_type('.'.join(ns[:-1]), contex, objs, funcs)
        return abs_type(pre[1]+'.'+ns[-1], contex, objs, funcs, False)
    return ('var', expr)

# 推导表达式类型
def eval_expr(path, line, contex, objs, funcs):
    line.replace('{}', 'dict')
    f = lambda x:x.group(0)[:-2]+'tuple'
    line = re.sub('[^\w\)\]]\(\)|^\(\)', f, line)
    f = lambda x:x.group(0)[:-2]+'list'
    line = re.sub('[^\w\)\]]\(\)|^\[\]', f, line)
    line = line.replace('()', '<>')
    ls = re.split('\+|\-|\*|\/|\(|\)|\^|~', line)
    ls = [i.replace('<>', '()').strip() for i in ls if i != '']
    ls = [abs_path(path, i, contex, objs, funcs) for i in ls]
    tps = [abs_type(i, contex, objs, funcs)[1] for i in ls]
    # print(tps, '>>>>>')

    if 'numpy.ndarray' in tps: return ('var', 'numpy.ndarray')
    if 'str' in tps: return ('var', 'str')
    if 'num' in tps: return ('var', 'num')
    if len(tps)==1: return ('var', tps[0])
    return ('var', 'uknown')
    
if __name__ == '__main__':
    cont_func = 'def f(a, b=5, c=[4], *args, **keys):'
    cont_class = 'class A(B, C, D):'
    cont_int = 'a=1, b=1.2, c 5'
    cont_expr = 'a = b, (c, d) = np.zeros(3, dtype=np.uint8), (2, 3)'
    cont_field = 'a = b, (c, d) = np.zeros(3, dtype=np.uint8), (2, 3)'
    a = parse_function(cont_func)
    b = parse_class(cont_class)
    c = find_num(cont_int)
    d = find_expr(cont_expr)
    e = parse_field(cont_field)

